package org.jeecg.modules.nikeProject.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.modules.nikeProject.entity.SportsCaseReportHis;
import org.jeecg.modules.nikeProject.entity.SportsProject;
import org.jeecg.modules.nikeProject.entity.vo.CaseCompareScore;
import org.jeecg.modules.nikeProject.entity.vo.CaseDetailVO;
import org.jeecg.modules.nikeProject.entity.vo.CaseReportVO;
import org.jeecg.modules.nikeProject.mapper.SportsCaseReportHisMapper;
import org.jeecg.modules.nikeProject.mapper.SportsCaseReportMapper;
import org.jeecg.modules.nikeProject.mapper.SportsProjectMapper;
import org.jeecg.modules.nikeProject.service.ISportsCaseReportHisService;
import org.jeecg.modules.system.mapper.SysDictMapper;
import org.jeecg.modules.util.JaccardSimilarity;
import org.jeecg.modules.util.ThreadPoolUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.xm.Similarity;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

/**
 * @Description: 历年获奖案例数据表
 * @Author: jeecg-boot
 * @Date:   2025-03-06
 * @Version: V1.0
 */
@Service
@Slf4j
public class SportsCaseReportHisServiceImpl extends ServiceImpl<SportsCaseReportHisMapper, SportsCaseReportHis> implements ISportsCaseReportHisService {

    @Autowired
    private SportsCaseReportHisMapper sportsCaseReportHisMapper;
    @Autowired
    private SportsProjectMapper sportsProjectMapper;
    @Autowired
    private SportsCaseReportMapper sportsCaseReportMapper;
    @Autowired
    private SysDictMapper sysDictMapper;

    @Override
    public Result<?> compareCaseContent(Integer year, Integer hisYear) {
        if (year == null) {
            Calendar calendar = Calendar.getInstance();
            year = calendar.get(Calendar.YEAR);
        }
        long currenttime = System.currentTimeMillis();
        //查询出当前年未去重的案例列表
        List<CaseReportVO> currentCaseReportVOList = sportsCaseReportMapper.getPendingCaseReports(year);
        log.info("当前需进行去重的数据为：{}条", currentCaseReportVOList.size());
        //查询出历年获奖案例的caseSummary
        List<SportsCaseReportHis> hisCaseReportVOList = sportsCaseReportHisMapper.getSportsCaseReportHis();
        log.info("历史案例比较案例为：{}条", hisCaseReportVOList.size());
//        ExecutorService executorService = Executors.newFixedThreadPool(20);
        for (CaseReportVO caseReportVO : currentCaseReportVOList){
            //进行比较去重
            compare2(caseReportVO, hisCaseReportVOList);
        }
        long endtime = System.currentTimeMillis();
        log.info("总计用时：{}", endtime-currenttime);
        return Result.OK("success");
    }

    public void updateRepitionRate(List<List<CaseCompareScore>> results, CaseReportVO currentCase){
        //从数据字典中取出去重比率
        String repetitonRate = sysDictMapper.getDictItemName(CommonConstant.REPETITION_RATE_DICT_CODE, "");
        BigDecimal rate = new BigDecimal(repetitonRate);
        List<CaseCompareScore> maxScores = new ArrayList<>();
        for (List<CaseCompareScore> subList : results) {
            if (!subList.isEmpty()) { // 确保子列表不为空，以避免NullPointerException
                Optional<CaseCompareScore> max = subList.stream().max(CaseCompareScore::compareTo);
                maxScores.add(max.orElse(null)); // 处理空列表的情况，这里理论上不应该有空列表，除非有特殊情况处理空列表的需求。
            } else {
                maxScores.add(null); // 或者你可以选择添加一个默认值或者不添加任何内容，取决于你的需求。
            }
        }

        CaseCompareScore maxScore =  Collections.max(maxScores, Comparator.comparing(CaseCompareScore::getRepetitionRate));
        log.info("与当前案例相比后，最终最大的重复率为：maxScore = {},历史案例ID为： HisProjectId= {}", maxScore.getRepetitionRate(), maxScore.getHisProjectId());
        SportsProject sportsProject = sportsProjectMapper.selectById(currentCase.getProjectId());
        sportsProject.setRepetitionRate(BigDecimal.valueOf(maxScore.getRepetitionRate()));
        sportsProject.setHisProjectId(maxScore.getHisProjectId());
        BigDecimal score = BigDecimal.valueOf(maxScore.getRepetitionRate());
        if (score.compareTo(rate) > 0 ){
            sportsProject.setFirstAuditStatus(CommonConstant.PROJECT_FIRST_AUDIT_STATUS_OUT);
        } else {
            sportsProject.setFirstAuditStatus(CommonConstant.PROJECT_FIRST_AUDIT_STATUS_FINISH);
        }
        sportsProjectMapper.updateById(sportsProject);
    }

    public void compare2(CaseReportVO caseReportVO, List<SportsCaseReportHis> hisCaseReportVOList){
        //处理完成后的结果集
        List<List<CaseCompareScore>> results = new ArrayList<>();
        log.info("===============分割线===================");
        log.info("===========使用多线程处理数据============");
        log.info("===============开始去重=================");
        long millis1 = System.currentTimeMillis();
        try {
            ThreadPoolUtil<List<CaseCompareScore>> threadPoolUtil = ThreadPoolUtil.getInstance();
            List<Future<List<CaseCompareScore>>> futureList = new ArrayList<>();
            //这里根据线程池的核心数去进行分段处理，最好不要一开始就达到最大线程数，只需要一半即可
            int numThreads = Runtime.getRuntime().availableProcessors() / 2;
    //        int numThreads = 30;
            for (int i = 0; i < hisCaseReportVOList.size(); i += hisCaseReportVOList.size() / numThreads) {
                int start = i;
                int end = Math.min(i + hisCaseReportVOList.size() / numThreads, hisCaseReportVOList.size());
                List<SportsCaseReportHis> subList = hisCaseReportVOList.subList(start, end);
                Callable<List<CaseCompareScore>> task = () -> {
                    return execute(subList, caseReportVO);
                };
                Future<List<CaseCompareScore>> future = threadPoolUtil.submitTask(task);
                futureList.add(future);
            }
            for (Future<List<CaseCompareScore>> future : futureList) {
                results.add(future.get());
            }
            updateRepitionRate(results, caseReportVO);
        }catch (Exception e){
            e.printStackTrace();
        }
        log.info("去重完成,去重析数据量:"+results.size()+",耗时:"+(System.currentTimeMillis() - millis1) / 1000 + "秒");

    }

    private static List<CaseCompareScore> execute(List<SportsCaseReportHis> subList, CaseReportVO currentCase){
        List<CaseCompareScore> results = new ArrayList<>();
        for (SportsCaseReportHis x : subList) {
            try {
                //模拟耗时每次1s
                Thread.sleep(1000);
                double jaccardSimilarityResult = JaccardSimilarity.jaccardSimilarity(currentCase.getCaseSummary(), x.getCaseSummary());
                log.info("当前案例：{} 和历史案例：{}，杰卡德相似度值为：{}", currentCase.getProjectId(), x.getProjectId(), jaccardSimilarityResult);
                //将比较出来的数据写入List中
                BigDecimal result = new BigDecimal(jaccardSimilarityResult).multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP);
                CaseCompareScore caseCompareScore = new CaseCompareScore();
                caseCompareScore.setProjectId(currentCase.getProjectId());
                caseCompareScore.setHisProjectId(x.getProjectId());
                caseCompareScore.setRepetitionRate(result.doubleValue()
                );
                results.add(caseCompareScore);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return results;
    }

    /**
     * 查看当前案例与去重案例的详细信息
     * @param projectId
     * @return
     */
    @Override
    public Result<?> checkDetail(String projectId) {
        Map<String, Object> resultMap = new HashMap<>();
        //当前案例相关信息
        CaseDetailVO currentCase = sportsCaseReportMapper.getCaseDetail(projectId);
        currentCase.setCourseStage(getCourseStage(currentCase.getCourseStage()));
        currentCase.setOtherCaseName(getOtherCaseName(currentCase.getCaseType(), currentCase.getOtherCase()));
        resultMap.put("currentCase", currentCase);

        // 历史案例相关信息
        LambdaQueryWrapper<SportsCaseReportHis> hisLambdaQueryWrapper = new LambdaQueryWrapper<>();
        hisLambdaQueryWrapper.eq(SportsCaseReportHis::getIzActive, CommonConstant.COMMON_STATUS_N)
                .eq(SportsCaseReportHis::getProjectId, currentCase.getHisProjectId());
        SportsCaseReportHis sportsCaseReportHis = sportsCaseReportHisMapper.selectOne(hisLambdaQueryWrapper);
        CaseDetailVO hisCase = new CaseDetailVO();
        if (null != sportsCaseReportHis) {
            String hisProjectId = sportsCaseReportHis.getProjectId();
            hisCase.setProjectId(hisProjectId);
            hisCase.setCaseSummary(sportsCaseReportHis.getCaseSummary());
            hisCase.setCaseName(sportsCaseReportHis.getCaseName());
            hisCase.setYear(sportsCaseReportHis.getYear());

            CaseDetailVO hisCaseDetailVO = sportsCaseReportMapper.getCaseDetail(hisProjectId);
            hisCase.setCaseTypeName(hisCaseDetailVO.getCaseTypeName());
            hisCase.setCourseStage(getCourseStage(hisCaseDetailVO.getCourseStage()));
            hisCase.setOtherCaseName(getOtherCaseName(hisCaseDetailVO.getCaseType(), hisCaseDetailVO.getOtherCase()));
        }
        resultMap.put("hisCase", hisCase);
        return Result.OK("success", resultMap);
    }

    public String getCourseStage(String courseStage){
        return sysDictMapper.getDictItemName("teach_stage", courseStage);
    }

    public String getOtherCaseName(String caseType, String otherCase) {
        String type = "";
        if (CommonConstant.CASE_TYPE_TEACH.equals(caseType)) {
            type = CommonConstant.CASE_TYPE_TEACH_EN;
        }
        if (CommonConstant.CASE_TYPE_CULTURE.equals(caseType)) {
            type = CommonConstant.CASE_TYPE_CULTURE_EN;
        }
        if (CommonConstant.CASE_TYPE_ACTIVITY.equals(caseType)) {
            type = CommonConstant.CASE_TYPE_ACTIVITY_EN;
        }
        if (CommonConstant.CASE_TYPE_OTHER.equals(caseType)) {
            type = CommonConstant.CASE_TYPE_OTHER_EN;
        }
        return sysDictMapper.getDictItemName(type, otherCase);
    }
    /**
     * 当前年的案例与历史获奖案例进行比较， 重复率高于85%则为未通过
     //* @param currentCase  当前案例
     //* @param hisCaseReportVOList
     */
    /* public void compare(CaseReportVO currentCase, List<SportsCaseReportHis> hisCaseReportVOList) {
        log.info("============开始进行去重比较============");
        BigDecimal rate = new BigDecimal("85");
        List<CaseCompareScore> list = new ArrayList<>();
        int threadNum =  Runtime.getRuntime().availableProcessors();
        log.info("最大可使用的CPU线程核心数= {}", threadNum);
        //计算每个分组存多个数据
        int capactiy = hisCaseReportVOList.size() % threadNum > 0 ? hisCaseReportVOList.size() / threadNum : hisCaseReportVOList.size() / threadNum + 1;
        //进行数据分组(分任务)例如，对包含[a，b，c，d，e]的列表进行分区，分区大小为3，得到[[a，b，c]，[d，e]]——一个包含三个和两个元素的两个内部列表的外部列表，所有列表都按原始顺序排列。
        List<List<SportsCaseReportHis>> partions = Lists.partition(hisCaseReportVOList, capactiy);
        // 保存结果
        List<Future<List<CaseCompareScore>>> futures = new ArrayList<Future<List<CaseCompareScore>>>(partions.size());

        ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
        for(SportsCaseReportHis x : hisCaseReportVOList){
            executorService.submit(() -> {
                double morphoSimilarityResult = Similarity.morphoSimilarity(currentCase.getCaseSummary(), x.getCaseSummary());
                log.info("当前案例：{} 和历史案例：{}，进行词形词序句子相似度值为：{}", currentCase.getProjectId(), x.getProjectId(), morphoSimilarityResult);
                //将比较出来的数据写入List中
                BigDecimal result = new BigDecimal(morphoSimilarityResult).multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP);
                CaseCompareScore caseCompareScore = new CaseCompareScore();
                caseCompareScore.setProjectId(currentCase.getProjectId());
                caseCompareScore.setHisProjectId(x.getProjectId());
                caseCompareScore.setRepetitionRate(result);
                list.add(caseCompareScore);
            });
            //距离相似性
//            double editDistanceResult = Similarity.editDistanceSimilarity(currentCase.getCaseSummary(), x.getCaseSummary());
//            log.info("当前案例：{} 和历史案例：{}，距离相似性值为：{}", currentCase.getProjectId(), x.getProjectId(), editDistanceResult);
            //编辑距离相似性
//            double standEditDistanceResult = Similarity.standardEditDistanceSimilarity(currentCase.getCaseSummary(), x.getCaseSummary());
//            log.info("当前案例：{} 和历史案例：{}，编辑距离相似性值为：{}", currentCase.getProjectId(), x.getProjectId(), standEditDistanceResult);

//            double gregeorEditDistanceResult = Similarity.gregorEditDistanceSimilarity(currentCase.getCaseSummary(), x.getCaseSummary());
//            log.info("当前案例：{} 和历史案例：{}，gregeor编辑距离相似性值为：{}", currentCase.getProjectId(), x.getProjectId(), gregeorEditDistanceResult);

//            double phraseSimilarityResult = Similarity.phraseSimilarity(currentCase.getCaseSummary(), x.getCaseSummary());
//            log.info("当前案例：{} 和历史案例：{}，短语相似度值值为：{}", currentCase.getProjectId(), x.getProjectId(), phraseSimilarityResult);
        }
        //如果重复率高于85%则将状态设置为淘汰案例，低于85则状态为已通过
        //取最大值
        CaseCompareScore maxScore =  Collections.max(list, Comparator.comparing(CaseCompareScore::getRepetitionRate));
        log.info("maxScore = {}, HisProjectId= {}", maxScore.getRepetitionRate(), maxScore.getHisProjectId());
        SportsProject sportsProject = sportsProjectMapper.selectById(currentCase.getProjectId());
        sportsProject.setRepetitionRate(maxScore.getRepetitionRate());
        sportsProject.setHisProjectId(maxScore.getHisProjectId());
        if (maxScore.getRepetitionRate().compareTo(rate) > 0 ){
            sportsProject.setFirstAuditStatus(CommonConstant.PROJECT_FIRST_AUDIT_STATUS_OUT);
        } else {
            sportsProject.setFirstAuditStatus(CommonConstant.PROJECT_FIRST_AUDIT_STATUS_FINISH);
        }
        sportsProjectMapper.updateById(sportsProject);
        executorService.shutdown();
        try {
            executorService.awaitTermination(1, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    } */

    public List<SportsCaseReportHis> getSportsCaseReportHis(Integer hisYear){
        LambdaQueryWrapper<SportsCaseReportHis> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SportsCaseReportHis::getIzActive, CommonConstant.COMMON_STATUS_N);
        if (null != hisYear) {
            lambdaQueryWrapper.eq(SportsCaseReportHis::getYear, hisYear);
        } else {
            lambdaQueryWrapper.in(SportsCaseReportHis::getYear, "2024,2023,2022");
        }
        lambdaQueryWrapper.isNotNull(SportsCaseReportHis::getCaseSummary);
        lambdaQueryWrapper.ne(SportsCaseReportHis::getCaseSummary, "ERROR");
        return sportsCaseReportHisMapper.selectList(lambdaQueryWrapper);
    }
}
